package com.netscenery.yang.model;

import java.util.ArrayList;

import org.jdom2.Element;

import com.netscenery.util.QName;
import com.netscenery.yang.YangStatement;
import com.netscenery.yang.designer.MapInfo;
import com.netscenery.yang.parser.YangParserException;

public class Deviate extends ModelElement{
	private boolean hasConfig = false;
	private boolean isConfig;
	private String defaultValue;
	private boolean hasMandatory = false;
	private boolean isMandatory;
	private boolean hasMaxElements = false;
	private int maxElements;
	private boolean hasMinElements = false;
	private int minElements;
	private ArrayList<Must> musts;
	private Type type;
	private ArrayList<String> uniques;
	private String units;
	
	
	public static final String NOTSUPPORTED = "not-supported";
	public static final String ADD = "add";
	public static final String REPLACE = "replace";
	public static final String DELETE = "delete";
	public Deviate() {
		// TODO Auto-generated constructor stub
	}

	public Deviate(Env env, QName qname) {
		super(env, qname);
		// TODO Auto-generated constructor stub
	}

	public Deviate(Env env, String name) throws ModelException {
		super(env, name);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean checkName(String name) {
		// TODO Auto-generated method stub
		if (!name.equals(NOTSUPPORTED)
				&& !name.equals(ADD)
				&& !name.equals(DELETE)
				&& !name.equals(REPLACE)){
			return false;
		}
		return true;
	}

	public boolean isConfig() {
		return isConfig;
	}

	public boolean setConfig(boolean isConfig) {
		Node curNode = env.getCurNode();
		if (null == curNode){
			return false;
		}
		if(name.equals(NOTSUPPORTED)){
			return false;
		}
		else if (name.equals(ADD)){
			if(!curNode.isUseDefaultConfig()){
				return false;
			}
		}
		else if (name.equals(DELETE)){
			if (curNode.isUseDefaultConfig()){
				return false;
			}
			if (curNode.isConfig() != isConfig){
				return false;
			}
		}
		else {
			if (curNode.isUseDefaultConfig()){
				return false;
			}
		}
		this.isConfig = isConfig;
		this.hasConfig = true;
		return true;
	}

	public String getDefaultValue() {
		return defaultValue;
	}

	public boolean setDefaultValue(String defaultValue) {
		if (null == defaultValue){
			return false;
		}
		
		if (!((env.getCurNode() instanceof Leaf)
				|| (env.getCurNode() instanceof Choice))){
			return false;
		}
		
		Node curNode = env.getCurNode();
		if (null == curNode){
			return false;
		}
		
		String targetDefaultValue = null;
		if (curNode instanceof Choice){
			Choice ch = (Choice) curNode;
			targetDefaultValue = ch.getDefaultValue();
		}
		else {
			Leaf l = (Leaf) curNode;
			targetDefaultValue = l.getDefaultValue();
		}
		if(name.equals(NOTSUPPORTED)){
			return false;
		}
		else if (name.equals(ADD)){
			if(null != targetDefaultValue){
				return false;
			}
		}
		else if (name.equals(DELETE)){
			if (null == targetDefaultValue){
				return false;
			}
			if (targetDefaultValue != defaultValue){
				return false;
			}
		}
		else {
			if (null == targetDefaultValue){
				return false;
			}
		}
		this.defaultValue = defaultValue;
		return true;
	}

	public boolean isMandatory() {
		return isMandatory;
	}

	public boolean setMandatory(boolean isMandatory) {
		if ((env.getCurNode() instanceof Leaf)
				|| (env.getCurNode() instanceof Choice)){
			
		}
		else {
			return false;
		}
		Node curNode = env.getCurNode();
		if (null == curNode){
			return false;
		}
		boolean targetUseDefaultMandatory = false;
		boolean targetMandatory = false;
		if (curNode instanceof Choice){
			Choice ch = (Choice) curNode;
			targetUseDefaultMandatory = ch.isUseDefaultMandatory();
			targetMandatory = ch.isMandatory();
		}
		else {
			Leaf l = (Leaf) curNode;
			targetUseDefaultMandatory = l.isUseDefaultMandatory();
			targetMandatory = l.isMandatory();
		}
		if(name.equals(NOTSUPPORTED)){
			return false;
		}
		else if (name.equals(ADD)){
			if(!targetUseDefaultMandatory){
				return false;
			}
		}
		else if (name.equals(DELETE)){
			if (targetUseDefaultMandatory){
				return false;
			}
			if (isMandatory != targetMandatory){
				return false;
			}
		}
		else {
			if (targetUseDefaultMandatory){
				return false;
			}
		}
		
		this.isMandatory = isMandatory;
		this.hasMandatory = true;
		return true;
	}

	public int getMaxElements() {
		return maxElements;
	}

	public boolean setMaxElements(int maxElements) {
		if ((env.getCurNode() instanceof YangList)
				|| (env.getCurNode() instanceof LeafList)){
			
		}
		else {
			return false;
		}
		
		Node curNode = env.getCurNode();
		if (null == curNode){
			return false;
		}
		
		boolean targetHasMaxElements = false;
		int targetMaxElement = 0;
		if (curNode instanceof YangList){
			YangList list = (YangList) curNode;
			if(list.isUseDefaultMaxElements()){
				targetHasMaxElements = false;
			}
			else {
				targetHasMaxElements = true;
				targetMaxElement = list.getMaxElements();
			}
		}
		else {
			LeafList l = (LeafList) curNode;
			if (l.isUseDefaultMaxElements()){
				targetHasMaxElements = false;
			}
			else{
				targetHasMaxElements = true;
				targetMaxElement = l.getMaxElements();
			}
		}
		
		if(name.equals(NOTSUPPORTED)){
			return false;
		}
		else if (name.equals(ADD)){
			if(targetHasMaxElements){
				return false;
			}
		}
		else if (name.equals(DELETE)){
			if (!targetHasMaxElements){
				return false;
			}
			if (maxElements != targetMaxElement){
				return false;
			}
		}
		else {
			if (!targetHasMaxElements){
				return false;
			}
		}
		
		this.maxElements = maxElements;
		this.hasMaxElements = true;
		return true;
	}

	public int getMinElements() {
		return minElements;
	}

	public boolean setMinElements(int minElements) {
		if ((env.getCurNode() instanceof YangList)
				|| (env.getCurNode() instanceof LeafList)){
			
		}
		else {
			return false;
		}
		
		Node curNode = env.getCurNode();
		if (null == curNode){
			return false;
		}
		
		boolean targetHasMinElements = false;
		int targetMinElement = 0;
		if (curNode instanceof YangList){
			YangList list = (YangList) curNode;
			if(list.isUseDefaultMinElements()){
				targetHasMinElements = false;
			}
			else {
				targetHasMinElements = true;
				targetMinElement = list.getMinElements();
			}
		}
		else {
			LeafList l = (LeafList) curNode;
			if (l.isUseDefaultMinElements()){
				targetHasMinElements = false;
			}
			else{
				targetHasMinElements = true;
				targetMinElement = l.getMinElements();
			}
		}
		
		if(name.equals(NOTSUPPORTED)){
			return false;
		}
		else if (name.equals(ADD)){
			if(targetHasMinElements){
				return false;
			}
		}
		else if (name.equals(DELETE)){
			if (!targetHasMinElements){
				return false;
			}
			if (minElements != targetMinElement){
				return false;
			}
		}
		else {
			if (!targetHasMinElements){
				return false;
			}
		}
		this.minElements = minElements;
		this.hasMinElements = true;
		return true;
	}

	public void setHasConfig(boolean hasConfig) {
		this.hasConfig = hasConfig;
	}

	public void setHasMandatory(boolean hasMandatory) {
		this.hasMandatory = hasMandatory;
	}

	public void setHasMaxElements(boolean hasMaxElements) {
		this.hasMaxElements = hasMaxElements;
	}

	public void setHasMinElements(boolean hasMinElements) {
		this.hasMinElements = hasMinElements;
	}

	public Type getType() {
		return type;
	}

	public boolean setType(Type type) {
		if ((env.getCurNode() instanceof Leaf)
				||(env.getCurNode() instanceof LeafList)){
			
		}
		else {
			return false;
		}
		
		Node curNode = env.getCurNode();
		if (null == curNode){
			return false;
		}
		Type targetType = null;
		if (curNode instanceof Leaf){
			Leaf l = (Leaf) curNode;
			targetType = l.getType();
		}
		else {
			LeafList ll = (LeafList) curNode;
			targetType = ll.getType();
		}
		if(name.equals(NOTSUPPORTED)){
			return false;
		}
		else if (name.equals(ADD)){
			return false;
		}
		else if (name.equals(DELETE)){

			if (!type.equals(targetType)){
				return false;
			}
		}
				
		this.type = type;
		
		return true;
	}

	public String getUnits() {
		return units;
	}

	public boolean setUnits(String units) {
		if ((env.getCurNode() instanceof Leaf)
				||(env.getCurNode() instanceof LeafList)){
			
		}
		else {
			return false;
		}
		
		Node curNode = env.getCurNode();
		if (null == curNode){
			return false;
		}
		
		
		String targetUnits = null;
		
		if (curNode instanceof Leaf){
			Leaf l = (Leaf) curNode;
			targetUnits = l.getUnits();
		}
		else {
			LeafList ll = (LeafList) curNode;
			targetUnits = ll.getUnits();
		}
		if(name.equals(NOTSUPPORTED)){
			return false;
		}
		else if (name.equals(ADD)){
			if(null != targetUnits){
				return false;
			}
		}
		else if (name.equals(DELETE)){
			if (null == targetUnits){
				return false;
			}
			if (!units.equals(targetUnits)){
				return false;
			}
		}
		else {
			if (null == targetUnits){
				return false;
			}
		}
		this.units = units;
		return true;
	}
	/**
	 * ��ȡMust����Ŀ
	 * @return
	 * @see com.netscenery.model.Must
	 */
	public int getMustsNumber(){
		if (null == this.musts){
			return 0;
		}
		return this.musts.size();
	}
	/**
	 * ���ָ������ƴ���Must
	 * @param name
	 * @return
	 * @throws ModelException 
	 * @see com.netscenery.model.Must
	 */
	public Must createMust(String name) throws ModelException{
		if (null == name){
			return null;
		}
		
		return new Must(newSubEnv(),name);
	}
	/**
	 * ���һ��Must
	 * @param n
	 * @return
	 * @see com.netscenery.model.Must
	 */
	public boolean addMust(Must n){
		if(null == n){
			return false;
		}
		
		if (null == this.musts){
			this.musts = new ArrayList<Must>(1);
		}
		if (null != this.getMust(n.getName())){
			return false;
		}
		return this.musts.add(n);
		

	}
	/**
	 * �����Ż�ȡMust
	 * @param index
	 * @return
	 * @see com.netscenery.model.Must
	 */
	public Must getMust(int index){
		if (null == this.musts){
			return null;
		}
		if (index >= this.musts.size()){
			return null;
		}
		return this.musts.get(index);
	}
	/**
	 * �����ƻ�ȡMust
	 * @param name
	 * @return
	 * @see com.netscenery.model.Must
	 */
	public Must getMust(String name){
		if (null == this.musts){
			return null;
		}
		int size = musts.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			Must n = this.musts.get(i);
			if (null != n){
				if (n.getName().equals(name)){
					return n;
				}
			}
		}
		return null;
	}
	/**
	 * ������ɾ��Must
	 * @param index
	 * @return Must
	 * @see com.netscenery.model.Must
	 */
	public Must removeMust(int index){
		if (null == this.musts){
			return null;
		}
		if (index >= this.musts.size()){
			return null;
		}
		return this.musts.remove(index);
	}
	/**
	 * ������ɾ��Must
	 * @param name
	 * @return Must
	 * @see com.netscenery.model.Must
	 */
	public Must removeMust(String name){
		if (null == this.musts){
			return null;
		}
		int size = musts.size();
		if (size <= 0){
			return null;
		}
		
		
		for (int i = 0; i < size; i++){
			Must n = this.musts.get(i);
			if (null != n){
				if (n.getName().equals(name)){
					return musts.remove(i);
				}
			}
		}
		return null;
	}
	
	/**
	 * ��ȡunique����Ŀ
	 * @return
	 */
	public int getUniquesNumber(){
		if (null == this.uniques){
			return 0;
		}
		return this.uniques.size();
	}
	
	public boolean checkUnique(String unique){
		if (null == unique){
			return false;
		}
		String[] uniqueNodes = unique.split(" ");
		int size = uniqueNodes.length;
		if (0 == size){
			return false;
		}
		Node curNode = env.getCurNode();
		if ( curNode == null){
			return false;
		}
	
		if (!(curNode instanceof YangList)){
			return false;
		}
		
		for (int i = 0; i < size; i++){
			String uniqueNode = uniqueNodes[i];
			if (null != uniqueNode){
				Node n = ModelElement.getNodeByDescendantPath(curNode.getEnv(), curNode, uniqueNode);
				if (null == n){
					return false;
				}
			}
		}
		
		
		
		return true;
	}
	/**
	 * ���һ��unique
	 * @param unique
	 * @return
	 */
	public boolean addUnique(String unique){
		if(null == unique){
			return false;
		}
		
		if (null == this.uniques){
			this.uniques = new ArrayList<String>(1);
		}
		if (this.hasUnique(unique)){
			return false;
		}
		return this.uniques.add(unique);
		

	}
	/**
	 * �����Ż�ȡunique
	 * @param index
	 * @return
	 */
	public String getUnique(int index){
		if (null == this.uniques){
			return null;
		}
		if (index >= this.uniques.size()){
			return null;
		}
		return this.uniques.get(index);
	}
	/**
	 * �жϵ�ǰunique�б����Ƿ����ָ����unique
	 * @param unique
	 * @return
	 */
	public boolean hasUnique(String unique){
		if (null == this.uniques){
			return false;
		}
		int size = uniques.size();
		if (size <= 0){
			return false;
		}
		
		for (int i = 0; i < size; i++){
			String n = this.uniques.get(i);
			if (null != n){
				if (n.equals(unique)){
					return true;
				}
			}
		}
		return false;
	}
	/**
	 * ������ɾ��unique
	 * @param index
	 * @return String

	 */
	public String removeUnique(int index){
		if (null == this.uniques){
			return null;
		}
		if (index >= this.uniques.size()){
			return null;
		}
		return this.uniques.remove(index);
	}
	/**
	 * ������ɾ��unique
	 * @param unique
	 * @return boolean
	 * @see com.netscenery.model.Must
	 */
	public boolean removeUnique(String unique){
		if (null == this.uniques){
			return false;
		}
		int size = uniques.size();
		if (size <= 0){
			return false;
		}
		
		
		for (int i = 0; i < size; i++){
			String n = this.uniques.get(i);
			if (null != n){
				if (n.equals(unique)){
					uniques.remove(i);
					return true;
				}
			}
		}
		return false;
	}
	@Override
	public YangStatement toYang() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Element toYin() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Element toXML() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int readXML(Element element) throws ModelException {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int readYin(Element element) throws ModelException {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int readYANG(YangStatement statement) throws YangParserException {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean isFieldMandatory(String field) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public MapInfo getMapInfo() throws SecurityException, NoSuchMethodException {
		// TODO Auto-generated method stub
		return null;
	}

	public Type createType(String builtinType,String derivedType){
		if (null == BuiltinType.getBuiltinType(builtinType)){
			return null;
		}
		Env subEnv = newSubEnv();
		if (null == derivedType){
			return Type.create(subEnv, builtinType);
		}
		Typedef type = null;
		
		QName qname = new QName(derivedType);
		type = Typedef.getDefByQName(env, qname);		
		if (null == type){
			return null;
		}
		
		if (!(type.getType().getBase().getFieldName().equals(builtinType))){
			return null;
		}
		
		return Type.create(subEnv, derivedType);
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		
	}
}
